#include "api.h"



////PRIVATE///////////////////////////
int ApiLinda::openFileDesc()
{
	int ret=0;
	ret = open("DESC", O_CREAT | O_EXCL, 07777);
	if(ret!=-1)close(ret);
	//DEBUG("openfiledesc", ret);
	fd=open(
			//schemaNameDESC.c_str()
			"DESC",	 O_CREAT | O_RDWR, 07777);//domyslnie jest do pisania czytania
	fk=open(//schemaNameDB.c_str()
			"DB",	 O_CREAT | O_RDWR, 07777);//domyslnie jest do pisania czytania

	Exception e;
	e.setS("Nie da sie otowrzyc ktorego z plików fd fk!");
	if (fk <=0 || fd <=0)
	{
		throw e;
	}

	return ret;
}

void ApiLinda::closeFileDesc()
{
	close(fd);
	close(fk);
}

int initsem(key_t key, int nsems)  /* key from ftok() */
{
    int i;
    union semun arg;
    struct semid_ds buf;
    struct sembuf sb;
    int semid;

    semid = semget(key, nsems, IPC_CREAT | IPC_EXCL | 0666);

    if (semid >= 0) { /* we got it first */
        sb.sem_op = 1; sb.sem_flg = 0;
        arg.val = 0;

        printf("press return\n"); getchar();

        for(sb.sem_num = 0; sb.sem_num < nsems; sb.sem_num++) {
            /* do a semop() to "free" the semaphores. */
            /* this sets the sem_otime field, as needed below. */
            if (semop(semid, &sb, 1) == -1) {
                int e = errno;
                semctl(semid, 0, IPC_RMID); /* clean up */
                errno = e;
                return -1; /* error, check errno */
            }
        }

    } else if (errno == EEXIST) { /* someone else got it first */
        int ready = 0;

        semid = semget(key, nsems, 0); /* get the id */
        if (semid < 0) return semid; /* error, check errno */

        /* wait for other process to initialize the semaphore: */
        arg.buf = &buf;
        for(i = 0; i < MAX_RETRIES && !ready; i++) {
            semctl(semid, nsems-1, IPC_STAT, arg);
            if (arg.buf->sem_otime != 0) {
                ready = 1;
            } else {
                sleep(1);
            }
        }
        if (!ready) {
            errno = ETIME;
            return -1;
        }
    } else {
        return semid; /* error, check errno */
    }

    return semid;
}




/////////////////////////////////////



ApiLinda::ApiLinda(string schemaName, int size)
{
	string MODULE_NAME("ApiLinda");

	std::string schemaNameDESC = schemaName + ".DESC";
	std::string schemaNameDB = schemaName+".DB";
//		DEBUG("",schemaNameDESC.c_str());
//		DEBUG("",schemaNameDB.c_str());
    int result=openFileDesc();
	descManager = new DesMenager(fd);
	if(result!=-1){
		DEBUG("Tworzenie plikow poniewaz nie znaleziono",1);
		descManager->resize(size);
	//descManager->createEmptyDes(size, 0);
	lseek(fk, 10000, SEEK_END);
	write(fk, "q", 1);
     }
	closeFileDesc();
}

ApiLinda::~ApiLinda()
{

	delete(descManager);
	closeFileDesc();
}




Record* ApiLinda::readLinda(string format)
{
	std::string MODULE_NAME("readLinda");

	int licznik = 0;
	while(licznik < 5)
	{
		Record* recordReturn = 0;

		recordReturn=searchLinda(format);
		if(recordReturn<=0)
		{
			DEBUGINFO(MODULE_NAME,"Spie..." << licznik);
			//sleep(2);
			++licznik;
		}
		else
		{
			descManager->unlock();
			return recordReturn;
		}
	}
	return 0;
}

Record* ApiLinda::inputLinda(string format)
{
	std::string MODULE_NAME("inputLinda");
	int licznik = 0;
	while(true)
	{
		DEBUG(MODULE_NAME, format);
		Record* record = searchLinda(format);

		//DEBUG(MODULE_NAME,record);
		if(record<=0)
		{
			DEBUGINFO(MODULE_NAME,"Spie..." << licznik);
			++licznik;
			lockSem();
		}
		else
		{
			openFileDesc();
			DEBUG(MODULE_NAME, this->lastPrecededTupleAdress);
			deleteRec(this->lastPrecededTupleAdress, descManager);
			descManager->unlock();
			closeFileDesc();
			return record;

		}

	}


	return 0;



}

void ApiLinda::outputLinda(string format)
{
	const string MODULE_ID = "outputLinda";
	openFileDesc();
	vector<string> tokensFields;
	vector<string> tokensAll;
	string delim1(",");
	Tokenize(format, tokensFields, delim1);
	DEBUG(MODULE_ID,tokensFields.size());
	vector<string>::iterator it;
	Command* cmdIn = new Command();

	struct sembuf sb;
	sb.sem_op = -1;
	sb.sem_num = 1;
	sb.sem_flg = 0;//IPC_NOWAIT;


	if(tokensFields.size() != ELEMENTCOUNT)
	{
		DEBUGINFO(MODULE_ID,"Nie dobra ilosc elementow")
		return;
		//exit(-1);
	}

	int elementFieldCounter = 0;
	for(it = tokensFields.begin(); it != tokensFields.end(); it++)
	{
		cmdIn->setElementFromQueryPartOut(*it,elementFieldCounter);
		++elementFieldCounter;
	}


//				DEBUG("",(int)cmdIn->type[0]);
//				DEBUG("",(int)cmdIn->type[1]);
//				DEBUG("",(int)cmdIn->type[2]);
//				DEBUG("",(int)cmdIn->type[3]);
//				DEBUG("",(int)cmdIn->type[4]);
	int result=saveNew(cmdIn, descManager, fd, fk);
	if(result==-1){//blad
		Exception ex;
		ex.setS("nie udalo sie wstawic krotki");
		closeFileDesc();
		delete(cmdIn);
		throw ex;
	}
	delete(cmdIn);
	setSemVal(getSemVal()-1);
	unlockSem();
	//DEBUG(MODULE_ID, semaphoreID);
	closeFileDesc();

}

Record* ApiLinda::searchLinda(string format)
{
	const string MODULE_NAME = "readLinda";
	DEBUG(MODULE_NAME,format);
	std::vector<string> tokensFields;
	Tokenize(format, tokensFields, ",");

	Command* cmdOut = new Command();
	int elementFieldCounter = 0;

	//DEBUGINFO(MODULE_NAME,"Podano warunkow:");
	//DEBUG(MODULE_NAME,tokensFields.size());

	for(int i=0 ; i < ELEMENTCOUNT ; i++)
	{
		if(i < tokensFields.size())
		{
			//DEBUG(MODULE_NAME,i);
		//	DEBUG(MODULE_NAME,tokensFields[i]);
			cmdOut->setElementFromQueryPartIn(tokensFields[i],i);
		}
		else
		{
	//		DEBUG(MODULE_NAME,i);
//			DEBUG(MODULE_NAME,"9");
			cmdOut->setElementFromQueryPartIn("9",i);
		}
	}

	openFileDesc();
	 Record* recordReturn = 0;
	//DEBUG(MODULE_NAME, 	(int)cmdOut);
	//DEBUG(MODULE_NAME, 	fk);
	//DEBUG(MODULE_NAME, 	(int)descManager);
	this->lastPrecededTupleAdress = search(cmdOut, descManager, fk, &recordReturn);
	delete(cmdOut);
	closeFileDesc();
	return recordReturn;
}

void ApiLinda::pisz()
{
	const string MODULE_ID = "pisz";
	openFileDesc();
	int dl=lseek(fd,0,SEEK_END);
	//DEBUG(MODULE_ID, dl);
	char *buf=new char[DESLENGTH];
	int i;
	int LiczbaKrotek=0;
	for( i=0;(i*DESLENGTH)<dl;++i)
	{
		RecordDescriptor des;
		Tuple k;

		int of=lseek(fd,(i*DESLENGTH), SEEK_SET);
		read(fd, buf, DESLENGTH);
		des.createFromBuf(buf);

		if(des.getBooked())
		{
			++LiczbaKrotek;
		unsigned int size=des.getSize();
		cout <<"@@@@@@@@@@@@        KROTKA"<<i<<"       @@@@@@@@@@@@@@@@@"<<endl;
		char *bufK=new char[size];
		lseek(fk, des.getOfset(), SEEK_SET);
		read(fk, bufK, size);
		k.createFromBuf(bufK, des.getType());
		des.wypisz();
		k.wypisz();
		}
	}

	DEBUG(MODULE_ID, LiczbaKrotek);

}

void ApiLinda::lockSem()
{
		 key_t key;
	    int semid;
	    struct sembuf sb;

	    sb.sem_num = 0;
	    sb.sem_op = -1;  /* set to allocate resource */
	    sb.sem_flg = SEM_UNDO;

	    if ((key = ftok(SEMAPHORE_PATH, 'J')) == -1) {
	        perror("ftok");
	        exit(1);
	    }

	    /* grab the semaphore set: */
	    if ((semid = initsem(key, 1)) == -1) {
	        perror("initsem");
	        exit(1);
	    }


	    if (semop(semid, &sb, 1) == -1) {
	        perror("semop");
	        exit(1);
	    }
}

void ApiLinda::unlockSem()
{
	 key_t key;
   int semid;
   struct sembuf sb;

   sb.sem_num = 0;
   sb.sem_op = 1;  /* set to allocate resource */
   sb.sem_flg = SEM_UNDO;

   if ((key = ftok(SEMAPHORE_PATH, 'J')) == -1) {
       perror("ftok");
       exit(1);
   }

   /* grab the semaphore set: */
   if ((semid = initsem(key, 1)) == -1) {
       perror("initsem");
       exit(1);
   }


   if (semop(semid, &sb, 1) == -1) {
       perror("semop");
       exit(1);
   }
}


void ApiLinda::setSemVal(int semVal)
{
	key_t key;
	int semid;
	struct sembuf sb;

	union semun uni;
	uni.val = semVal;

	sb.sem_num = 0;
	sb.sem_op = 1; /* free resource */
	sb.sem_flg = SEM_UNDO;

	if ((key = ftok(SEMAPHORE_PATH, 'J')) == -1)
	{
	   perror("ftok");
	   exit(1);
	}

	/* grab the semaphore set: */
	if ((semid = initsem(key, 1)) == -1)
	{
	   perror("initsem");
	   exit(1);
	}

	semctl(semid,0, SETVAL, uni);
}


int ApiLinda::getSemVal()
{
	key_t key;
	int semid;
	struct sembuf sb;

	union semun uni;

	sb.sem_num = 0;
	sb.sem_op = 1; /* free resource */
	sb.sem_flg = SEM_UNDO;

	if ((key = ftok(SEMAPHORE_PATH, 'J')) == -1)
	{
	   perror("ftok");
	   exit(1);
	}

	/* grab the semaphore set: */
	if ((semid = initsem(key, 1)) == -1)
	{
	   perror("initsem");
	   exit(1);
	}

	return semctl(semid,0, GETVAL, uni);

}

